<template>
  <div>
    <!-- el-form 是elementui 的form组件   model为绑定的对象   rules为 校验规则  ref为组件唯一属性   -->
    <el-form
        :model="formLogin"
        :rules="rules"
        ref="formLogin"
        label-width="100px"
    >
      {{formLogin}}

      <!--el-form-item为for组件的子项  prop属性为属性名,对应的是字段名 -->
      <el-form-item prop="username">

        <!--el-input 为input输入框  v-model为绑定的值 placeholder为提示  :placeholder  :是动态绑定,就等同于v-model:placeholder  动态绑定placeholder值
          @keyup.enter.native 键盘按回车绑定的一个操作  prefix-icon 是input是一个属性,icon-->
        <el-input
            v-model="formLogin.username"
            prefix-icon="el-icon-user-solid"
            :placeholder="$t('m.Login_Username')"
            width="100%"
            @keyup.enter.native="enterHandleLogin"
        ></el-input>
      </el-form-item>
      <el-form-item prop="password">
        <!--   type="password"   type是input标签的一个属性, 不填的话就是直接展示,为password的话 展示的话就是*****-->
        <el-input
            v-model="formLogin.password"
            prefix-icon="el-icon-lock"
            :placeholder="$t('m.Login_Password')"
            type="password"
            @keyup.enter.native="enterHandleLogin"
        ></el-input>
      </el-form-item>
      <!--  新----------------------------------------------------------------------------    -->
      <el-form-item prop="nickname">
        <el-input
            v-model="formLogin.nickname"
            prefix-icon="el-icon-user-solid"
            :placeholder="$t('m.Login_Nickname')"
            width="100%"
            @keyup.enter.native="enterHandleLogin"
        ></el-input>
      </el-form-item>

    </el-form>
    <!-- 底部按钮-->
    <div class="footer">
      <!-- 调用handleLogin 方法   v-if 就理解if判断  当为true的的时候  这个标签显示,  为false的时候不显示
      :loading 是一个等待缓冲加载 type 是按钮的类型  t('m.Login_Btn')  取i18n里面配置的值, i18n是多语言支持,
      意思就是一个属性,可以配置多种语言, 达到在不同的语言下展示不同的文字    -->
      <el-button
          type="primary"
          v-if="!needVerify"
          @click="handleLogin"
          :loading="btnLoginLoading"
      >{{ $t('m.Login_Btn') }}
      </el-button
      >
      <!--  element ui的弹框组件  这也是一个登录框, 主要是用来处理登录滑动验证码的,就是等失败次数过多的时候,前端触发滑动验证码-->
      <el-popover
          placement="bottom"
          width="350"
          v-model="loginSlideBlockVisible"
          trigger="click"
          v-else
      >
        <!-- 登录按钮-->
        <el-button type="primary" :loading="btnLoginLoading" slot="reference">{{
          $t('m.Login_Btn')
          }}
        </el-button>
        <!-- 滑动验证码-->
        <slide-verify
            :l="42"
            :r="10"
            :w="325"
            :h="100"
            :accuracy="3"
            :imgs="imgs"
            @success="handleLogin"
            :slider-text="$t('m.Slide_Verify')"
            ref="slideBlock"
            v-if="!verify.loginSuccess"
        >
        </slide-verify>
        <!-- 当登录成功的时候,提示-->
        <el-alert
            :title="$t('m.Slide_Verify_Success')"
            type="success"
            :description="verify.loginMsg"
            v-show="verify.loginSuccess"
            :center="true"
            :closable="false"
            show-icon
        >
        </el-alert>
      </el-popover>
      <el-link
          v-if="websiteConfig.register"
          type="primary"
          @click="switchMode('Register')"
      >{{ $t('m.Login_No_Account') }}
      </el-link
      >
      <el-link
          type="primary"
          @click="switchMode('ResetPwd')"
          style="float: right"
      >{{ $t('m.Login_Forget_Password') }}
      </el-link
      >
    </div>
  </div>
</template>
<script>
//  引入
//  引入 vuex里面的 mapGetters、mapActions 这两个方法到本页面中
import {mapGetters, mapActions} from 'vuex';
// import api(名称(类似于java的new的实例名)) from '@/common/api'(引入的文件);
// 这种的话就是引入 api.js 这个文件,而且起名为api,  调用的话就是api.xxx方法
import api from '@/common/api';
import mMessage from '@/common/message';

export default {
  // data 函数对象,这里面存放了vue组件的属性，这些属性可以在template(模板) 中使用, 当他们发现变化的时候,模板里面对应的值也也会自动更新
  data() {
    return {
      // 登录按钮加载中是否显示
      btnLoginLoading: false,
      // 是否需要验证码
      verify: {
        // 登录是否成功
        loginSuccess: false,
        // 登录信息
        loginMsg: '',
      },
      // 是否让登录，登录失败次数过多的话 就不让出来登录框了  这个值就是false了
      needVerify: false,
      // 表单绑定的对象
      formLogin: {
        // 用户名
        username: '',
        // 密码
        password: '',
        // 昵称
        nickname: ''  //新---------------------------------------------
      },
      // 验证码的图片
      imgs: [
        "https://picsum.photos/325/100?random=1",
        "https://picsum.photos/325/100?random=2",
        "https://picsum.photos/325/100?random=3",
        "https://picsum.photos/325/100?random=4",
        "https://picsum.photos/325/100?random=5",
        "https://picsum.photos/325/100?random=6",
        "https://picsum.photos/325/100?random=7",
        "https://picsum.photos/325/100?random=8",
        "https://picsum.photos/325/100?random=9",
        "https://picsum.photos/325/100?random=10"
      ],
      //验证码是否需要显示
      loginSlideBlockVisible: false,
      // 校验规则
      rules: {
        username: [
          {
            // 是否必填
            required: true,
            // 提示语
            message: this.$i18n.t('m.Username_Check_Required'),
            // trigger: 决定了验证规则何时被触发。
            // 常见的触发时机有： blur: 当输入框失去焦点时触发验证。 change: 当表单项的值发生改变时触发验证。
            // 对于选择器（如 Select）、多选框（Checkbox）和单选框（Radio），默认情况下blur是唯一有效的触发方式。
            trigger: 'blur',
          },
          {
            // 最大长度 20
            max: 20,
            message: this.$i18n.t('m.Username_Check_Max'),
            trigger: 'blur',
          },
        ],
        password: [
          {
            required: true,
            message: this.$i18n.t('m.Password_Check_Required'),
            trigger: 'blur',
          },
          {
            // 最小长度
            min: 6,
            // 最大长度
            max: 20,
            message: this.$i18n.t('m.Password_Check_Between'),
            trigger: 'blur',
          },
        ],
        nickname: [  //新-------------------------------------------------------------
          {
            required: true,
            message: this.$i18n.t('m.Nickname_Check_Required'),
            trigger: 'blur',
          },
          {
            max: 20,
            message: this.$i18n.t('m.Nickname_Check_Max'),
            trigger: 'blur',
          },
        ],
      },
    };
  },
  // 这里面写的是方法,当前页面所有需要调用的方法都写在这里面, 比如登录的方法、修改某个属性的方法
  methods: {
    //mapActions 是vuex里面的一个方法, 可以把vuex中的actions里面的方法映射到当前页面中,  ...是vue的调用 vuex的语法
    ...mapActions(['changeModalStatus']),
    // 当前弹框是否需要显示
    switchMode(mode) {
      this.changeModalStatus({
        mode,
        visible: true,
      });
    },
    enterHandleLogin() {

     // 当需要验证的时候, 弹出滑动验证码
      if (this.needVerify) {
        this.visible.loginSlideBlock = true;
      } else {
        // 如果没有的话 就直接调用登录方法
        this.handleLogin();
      }
    },
    handleLogin(times) {


      if (this.needVerify) {
        //  设置 loginSuccess 为true，表示验证或登陆成功
        this.verify.loginSuccess = true;
        //计算总时间（从毫秒抓换为秒），并保留一位小数
        let time = (times / 1000).toFixed(1);
        //更新消息显示总用时
        this.verify.loginMsg = 'Total time ' + time + 's';
        // 延时1000毫秒后执行 setTimeout(就是个定时器,指定多少毫秒后执行代码)
        setTimeout(() => {
          //隐藏滑块组件
          this.loginSlideBlockVisible = false;
          this.verify.loginSuccess = false;
        }, 1000);
      }

      // refs是vue的一个内置对象,用来访问子组件元素或者dom元素  $refs['formLogin'] 就是从vue中获取到ref = formLogin 这个组件  formLogin 是上面的el-form 中ref定义的
      // validate  是参数校验, 执行的是rules 的校验规则
      this.$refs['formLogin'].validate((valid) => {
        // valid 是校验结果 为true 或者false
        if (valid) {
          // 当校验成功的时候
          // 设置登录按钮加载为true, 这个页面页面就会在加载中
          this.btnLoginLoading = true;
          // Object.assign(target,source) 对象拷贝复制方法, 下面代码的意思就是把为空的{}和 formLogin对象拷贝到formData中

          let formData = Object.assign({}, this.formLogin);
          // 调用 api.login方法,方法的参数为formData  Promise是异步运算,  api.login方法返回的是Promise,  then是成功的时候执行的方法
          api.login(formData).then(
              (res) => {
                console.log(res);
                // res api.login 里面调用接口返回的后端的数据
                alert(JSON.stringify(res.data))
                //  让加载中去掉  但是调用接口 执行的时候会很快,所以 页面出现加载中和加载中去掉 几乎不可见
                this.btnLoginLoading = false;
                 // 隐藏登录的这个弹框
                this.changeModalStatus({visible: false});
                // 从返回结果header头部中authorization
                const jwt = res.headers['authorization'];

                // $store  vue状态管理库, 集中式存储管理应用的所有组件的状态  代码体现在 src/store/user.js 中
                // commit 是同步的调用changeUserToken 方法
                this.$store.commit('changeUserToken', jwt);
                // 异步的调用setUserInfo方法
                this.$store.dispatch('setUserInfo', res.data.data);
                this.$store.dispatch('incrLoginFailNum', true);
                //  提示信息 提示登录成功了
                mMessage.success(this.$i18n.t('m.Welcome_Back'));
              },
              // _ 是失败的回调
              (_) => {
                // 这里是访问接口失败的时候的逻辑
                this.$store.dispatch('incrLoginFailNum', false);
                this.btnLoginLoading = false;
              }
          );
        }
      });
    },
  },
  // computed 计算属性
  // 当依赖的数据进行变化的时候,计算属性会重新计算结果
  // 也可以定义 getter 和 setter（可选），使计算属性可以被读取和写入。
  computed: {
    // 定义 getter 和 setter（可选），使属性可以被读取和写入。
    ...mapGetters(['modalStatus', 'loginFailNum', 'websiteConfig']),
    visible: {
      get() {
        return this.modalStatus.visible;
      },
      set(value) {
        this.changeModalStatus({visible: value});
      },
    },
  },
  // watch 监听   监听某个属性的值变化,并在他们变化的时候执行相应的逻辑
  watch: {
    // 这里监听的就是 loginFailNum newVal 是变化后的值(新值) oldVal 是变化前的值(旧值)
    loginFailNum(newVal, oldVal) {
      // 当 大于5的时候, 设置 needVerify 为true

      if (newVal >= 5) {
        this.needVerify = true;
      } else {
        // 当 小于5的时候, 设置 needVerify 为false
        this.needVerify = false;
      }
    },
  },
};
</script>
<!-- style 这里放的是样式-->
<style scoped>

.footer {
  overflow: auto;
  margin-top: 20px;
  margin-bottom: -15px;
  text-align: left;
}

/deep/ .el-button {
  margin: 0 0 15px 0;
  width: 100%;
}

/deep/ .el-form-item__content {
  margin-left: 0px !important;
}
</style>
